#ifndef CLongScreenShotInApp_H
#define CLongScreenShotInApp_H

#include <QObject>
#include <QQmlEngine>
#include <QQuickWindow>
#include <QWindow>
#include <QStringListModel>

/**
 *  长截图
 *
 *  长截图是在应用侧实现，初始化需要提供应用的 QQmlEngine 指针，自动找到 Window 和 滚动区。
 *  调用 start() 启动长截图。默认会自动截取滚动区的四页图片，保存到目录中。
 *  保存位置可通过 setSavePath() 修改。截取的切图列表通过 model() 对外提供。
 *  这是有顺序的，可使用 Model 配合 ListView 或其他组件，实现长截图的实时预览，每多一张截图 Model 会自动更新。
 *
 *  需要手动调用 scrollAndGrab() 继续截取一些图片。截取多少由用户决定，可自动，可手动。
 *  截取过程中如果到底了，会发出 finished() 信号，通知长截图结束。
 *
 *  调用 save() 将会拼接 model() 中的切图列表为长截图。并返回绝对路径的文件名。
 * */

class CLongScreenShotInApp : public QObject
{
    Q_OBJECT
public:
    explicit CLongScreenShotInApp(QQmlEngine *engine, QObject *parent = nullptr);

signals:
    void finished(); //长截图结束
public slots:
    /**
    * @brief 启动长截图。
    *
    * 此函数启动长截图，如果没有到底，则截取固定长度，保存图片为文件，并发出 grabUpdate() 信号，传递文件绝对路径。
    * 如果截图时滚到到底则代表截图结束，会发出 finshed() 信号。
    *
    * @return 返回截图的共享指针，截图失败返回空。
    */
    bool start();

    /**
    * @brief 从滚动区当前位置截取指定长度的图片。
    *
    * @param window 需要截图的 QWindow.
    * @param scrollAreaItem 滚动控件的指针.
    * @param savePath 用于存储临时图片的目录.
    * @param pageCount 需要截取的页数，一个滚动区域的高度算一页.
    * @return 返回截图的共享指针，截图失败返回空。
    */
    void scrollAndGrab(int pageCount = 4);

    /**
    * @brief 长截图是否结束了。
    *
    * 判断长截图是否结束。
    *
    * @return 已结束返回 true，否则 false。
    */
    bool isFinished();

    /**
    * @brief 长截图的切图列表。
    *
    * 返回长截图未拼接的图片 Model，新增截图时 Model 自动更新。
    *
    * @return 未拼接的截图列表。
    */
    QStringListModel *model();

    /**
    * @brief 拼接多个截图为长截图并保存。
    *
    * 将长截图过程中的产生的图片拼接为长图并保存。
    *
    * @param fileName 长截图文件名，不带路径.
    * @return 保存成功返回长图文件名，失败返回空字符串。
    */
    QString save(QString fileName = "longScreenShot.png");
private:
    /**
    * @brief 重置长截屏状态。
    *
    * 此函数重置状态，清空 Model，并清空切图目录中的切图。
    *
    * @param engine 用于搜索窗口的 QQmlEngine.
    * @return 返回激活的 QQuickWindow 窗口指针，未找到则为 nullptr。
    */
    void reset();

    /**
    * @brief 从指定的 QQmlEngine 中找到滚动区 激活的 QQuickWindow。
    *
    * 此函数搜索 QQmlEngine 中的 QQuickWindow。
    * 如果是通过 QQmlApplicationEngine 创建窗口的， 从 rootObjects 中可以找到。
    * 如果是通过 QQuickView 创建的窗口，从 QQmlEngine::parent() 中可以找到。
    *
    * @param engine 用于搜索窗口的 QQmlEngine.
    * @return 返回激活的 QQuickWindow 窗口指针，未找到则为 nullptr。
    */
    QQuickWindow *findActiveWindw(QQmlEngine *engine);

    /**
    * @brief 从指定的 QWindow 中找到滚动区 Item。
    *
    * 此函数搜索 QWindow 中的 QQuickFlickable,QQuickListView, and QQuickGridView items。
    * 通过是否可见、Item位置、大小、是否是垂直长列表，判断出那个才是可长截图的滚动区，由于 QQuickFlickable,QQuickListView,QQuickGridView
    * 属于 Qt 内部私有类，所以返回 QQuickItem 指针。可通过 setProperty(),property() 操作滚动区。
    *
    * @param window 用于搜索滚动区的 QWindow.
    * @return 表示当前滚动区域的QQuickItem指针，如果没有找到滚动区域，则为 nullptr。
    */
    QQuickItem *findScrollArea(QWindow *window);

    /**
    * @brief 抓取指定 QWindow 截图。
    *
    * 此函数返回指定 QWindow 的截图。
    *
    * @param window 需要截图的 QWindow.
    * @return 返回截图的共享指针，截图失败返回空。
    */
    QSharedPointer<QImage> grabWindow(QWindow *window);

    /**
    * @brief 从滚动区当前位置截取指定长度的图片。
    *
    * @param window 需要截图的 QWindow.
    * @param scrollAreaItem 滚动控件的指针.
    * @param savePath 用于存储临时图片的目录.
    * @param pageCount 需要截取的页数，一个滚动区的高度算一页.
    * @return 返回截图的共享指针，截图失败返回空。
    */
    void scrollAndGrab(QWindow *window, QQuickItem *scrollAreaItem, const QString &savePath, int pageCount);

    /**
    * @brief 设置长截图产生切图的保存位置。
    *
    * 长截图过程中的临时图片和拼接后的长截图存储位置。
    *
    * @param path 截图的存储目录.
    * @return 无返回值。
    */
    void setSavePath(QString path);

    /**
    * @brief 设置长截图结束。
    *
    * 长截图滚动到底部会设置结束。
    *
    * @param ok 是否结束.
    * @return 无返回值。
    */
    void setFinished(bool ok);

    void clearDirectory(const QString& dirPath);            //清除文件夹中的所有文件
    void appendToModel(const QString &fileName);            //追加文件名称到 Model 末尾
    void insertToModel(int index, const QString &fileName); //指定位置插入文件名称到 Model
    QString getAbsolutePath(const QString& fileName);       //从文件名中获取绝对路径的文件名
    QString titleImageFileName();                           //拼接标题切图名
    QString appBarImageFileName();                          //拼接导航切图名
private:
    QString m_strSavePath = ".";                //默认的图片目录
    QQmlEngine *m_pEngine = nullptr;            //长截图窗口的qml引擎
    QWindow *m_pCurrentWindow = nullptr;        //当前长截图的主窗口
    QQuickItem *m_pCurrenScrollArea = nullptr;  //当前长截图的滚动区控件
    int m_nContentIndex = 0;                    //当前长截图的内容区的截图个数
    int m_nLongScreenHeight;                    //当前长截图高度
    bool m_bFinished = false;                   //长截图是否结束
    QStringListModel m_modelImages;             //长截图的图片列表，存的绝对路径，方便qml显示
};

#endif // CLongScreenShotInApp_H
